import json
import re
import asyncio
import aiohttp
from django.http import StreamingHttpResponse
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from django.utils import timezone
from asgiref.sync import async_to_sync
from chatLLM.models import ChatAppKey, ChatHistory, OllamaList
from .serializers import OllamaListSerializer
from chat_widget_dj.settings import OLLAMA_IP


async def stream_ollama_response(select_model, user_input):
    """
    异步函数，用于与 Ollama 服务进行流式交互。
    """
    ollama_url = f'http://{OLLAMA_IP}/api/chat'
    ollama_payload = {
        "model": select_model,
        "messages": user_input
    }
    headers = {
        "Accept": "text/event-stream",
        "Content-Type": "application/json"
    }
    timeout = aiohttp.ClientTimeout(total=60)  # 设置超时时间为 60 秒
    session = aiohttp.ClientSession(timeout=timeout)
    try:
        async with session.post(ollama_url, json=ollama_payload, headers=headers) as response:
            if response.status != 200:
                response_text = await response.text()
                print(f"非 200 状态码响应内容: {response_text}")
                yield f"data: {json.dumps({'error': 'Ollama 服务请求失败'})}\n\n"
                return

            async for line in response.content:
                if line:
                    decoded_line = line.decode('utf-8')
                    try:
                        chunk = json.loads(decoded_line)
                        if 'message' in chunk and 'content' in chunk['message']:
                            yield f"data: {json.dumps({'response': chunk['message']['content']})}\n\n"
                    except json.JSONDecodeError as e:
                        print(f"JSON 解析错误: {e}, 原始数据: {decoded_line}")
                        yield f"data: {json.dumps({'error': '数据解析失败'})}\n\n"
    except aiohttp.ClientError as e:
        print(f"请求发生错误: {e}")
        yield f"data: {json.dumps({'error': '请求 Ollama 服务失败'})}\n\n"
    finally:
        await session.close()


class ChatInteractionView(APIView):
    """
    处理聊天交互的视图类，支持流式响应。
    """
    authentication_classes = []

    def post(self, request, *args, **kwargs):
        """
        处理 POST 请求，返回流式响应。
        """
        try:
            # 验证 Authorization 头信息
            auth_header = request.headers.get('Authorization')
            if not auth_header:
                return Response({'error': '未提供 Authorization 头信息'}, status=status.HTTP_401_UNAUTHORIZED)

            match = re.match(r'^Bearer (\S+)$', auth_header)
            if not match:
                return Response({'error': 'Authorization 头信息格式错误'}, status=status.HTTP_401_UNAUTHORIZED)

            app_key = match.group(1)

            # 验证 AppKey
            try:
                chat_app_key = ChatAppKey.objects.get(app_key=app_key)
            except ChatAppKey.DoesNotExist:
                return Response({'error': '无效的 APPKEY'}, status=status.HTTP_401_UNAUTHORIZED)

            # 获取请求数据
            data = request.data
            select_model = data.get('model')
            messages = data.get('messages')

            # 更新 AppKey 的使用信息
            chat_app_key.last_used_at = timezone.now()
            api_name = 'chat_interaction'
            api_get_num = chat_app_key.api_get_num or {}
            api_get_num[api_name] = api_get_num.get(api_name, 0) + 1
            chat_app_key.api_get_num = api_get_num
            chat_app_key.save()

            # 将异步生成器转换为同步生成器
            def event_stream():
                async_gen = stream_ollama_response(select_model, messages)
                loop = asyncio.new_event_loop()
                asyncio.set_event_loop(loop)
                try:
                    while True:
                        try:
                            event = loop.run_until_complete(async_gen.__anext__())
                            yield event
                        except StopAsyncIteration:
                            break
                finally:
                    # 显式关闭异步生成器
                    loop.run_until_complete(async_gen.aclose())
                    loop.close()

            # 返回流式响应
            response = StreamingHttpResponse(event_stream(), content_type='text/event-stream')
            response['Cache-Control'] = 'no-cache'
            return response

        except Exception as e:
            print(f'Error: {str(e)}')
            return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


class GetModelListAPIView(APIView):
    authentication_classes = []

    def get(self, request):
        ollama_list = OllamaList.objects.all()
        serializer = OllamaListSerializer(ollama_list, many=True)
        return Response(serializer.data, status=status.HTTP_200_OK)


class GetAppKeyInfoAPIView(APIView):
    authentication_classes = []

    def get(self, request):
        auth_header = request.headers.get('Authorization')
        if not auth_header:
            return Response({'error': '未提供 Authorization 头信息'}, status=status.HTTP_401_UNAUTHORIZED)

        match = re.match(r'^Bearer (\S+)$', auth_header)
        if not match:
            return Response({'error': 'Authorization 头信息格式错误'}, status=status.HTTP_401_UNAUTHORIZED)

        app_key = match.group(1)

        try:
            chat_app_key = ChatAppKey.objects.get(app_key=app_key)
            chat_app_key.last_used_at = timezone.now()
            api_name = 'get_appkey_info'
            api_get_num = chat_app_key.api_get_num or {}
            api_get_num[api_name] = api_get_num.get(api_name, 0) + 1
            chat_app_key.api_get_num = api_get_num
            chat_app_key.save()

            data = {
                'select_model': chat_app_key.select_model,
                'api_get_num': chat_app_key.api_get_num,
                'token_get_num': chat_app_key.token_get_num,
                'system_model': chat_app_key.system_model
            }
            return Response(data, status=status.HTTP_200_OK)
        except ChatAppKey.DoesNotExist:
            return Response({'error': '无效的 APPKEY'}, status=status.HTTP_401_UNAUTHORIZED)
        except Exception as e:
            print(f'Error: {str(e)}')
            return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


class SetAppKeyInfoAPIView(APIView):
    authentication_classes = []

    def post(self, request):
        auth_header = request.headers.get('Authorization')
        if not auth_header:
            return Response({'error': '未提供 Authorization 头信息'}, status=status.HTTP_401_UNAUTHORIZED)

        match = re.match(r'^Bearer (\S+)$', auth_header)
        if not match:
            return Response({'error': 'Authorization 头信息格式错误'}, status=status.HTTP_401_UNAUTHORIZED)

        app_key = match.group(1)

        try:
            chat_app_key = ChatAppKey.objects.get(app_key=app_key)
            select_model = request.data.get('select_model')
            system_model = request.data.get('system_model')

            if select_model:
                chat_app_key.select_model = select_model
            if system_model:
                chat_app_key.system_model = system_model

            chat_app_key.last_used_at = timezone.now()
            api_name ='set_appkey_info'
            api_get_num = chat_app_key.api_get_num or {}
            api_get_num[api_name] = api_get_num.get(api_name, 0) + 1
            chat_app_key.api_get_num = api_get_num
            chat_app_key.save()

            return Response({'message': '设置保存成功'}, status=status.HTTP_200_OK)
        except ChatAppKey.DoesNotExist:
            return Response({'error': '无效的 APPKEY'}, status=status.HTTP_401_UNAUTHORIZED)
        except Exception as e:
            print(f'Error: {str(e)}')
            return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


class NewChatInteractionView(APIView):
    authentication_classes = []

    def post(self, request, *args, **kwargs):
        auth_header = request.headers.get('Authorization')
        if not auth_header:
            return Response({'error': '未提供 Authorization 头信息'}, status=status.HTTP_401_UNAUTHORIZED)

        match = re.match(r'^Bearer (\S+)$', auth_header)
        if not match:
            return Response({'error': 'Authorization 头信息格式错误'}, status=status.HTTP_401_UNAUTHORIZED)

        app_key = match.group(1)

        try:
            chat_app_key = ChatAppKey.objects.get(app_key=app_key)
        except ChatAppKey.DoesNotExist:
            return Response({'error': '无效的 APPKEY'}, status=status.HTTP_401_UNAUTHORIZED)

        data = request.data
        select_model = data.get('model')
        messages = data.get('messages')
        chat_history_id = data.get('ChatHistoryID')

        # print(f"收到请求，APPKEY: {app_key}, 输入: {messages}, 模型: {select_model}, 系统提示: {chat_history_id}")

        if not select_model or not messages:
            return Response({'error': '缺少必要的参数 model 或 messages'}, status=status.HTTP_400_BAD_REQUEST)

        chat_title = None
        for message in messages:
            if message.get('role') == 'user':
                chat_title = message.get('content')
                break

        if not chat_title:
            return Response({'error': 'messages 中未找到 role 为 user 的消息'}, status=status.HTTP_400_BAD_REQUEST)

        if chat_history_id is None:
            try:
                chat_history = ChatHistory(
                    from_app_key=chat_app_key.app_key,
                    select_model=select_model,
                    chat_title=chat_title,
                    chat_json=messages
                )
                chat_history.save()
                chat_history_id = chat_history.id
            except Exception as e:
                print(f"Error creating chat history: {e}")
                return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
        else:
            try:
                chat_history = ChatHistory.objects.get(id=chat_history_id)
                chat_history.chat_json = messages
                chat_history.save()
            except ChatHistory.DoesNotExist:
                return Response({'error': '未找到对应的聊天历史记录'}, status=status.HTTP_404_NOT_FOUND)
            except Exception as e:
                print(f"Error updating chat history: {e}")
                return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        chat_app_key.last_used_at = timezone.now()
        api_name = 'new_chat_interaction'
        api_get_num = chat_app_key.api_get_num or {}
        api_get_num[api_name] = api_get_num.get(api_name, 0) + 1
        chat_app_key.api_get_num = api_get_num
        chat_app_key.save()

        return Response({'chat_history_id': chat_history_id}, status=status.HTTP_200_OK)
